﻿namespace _5_NovaAdmin.Infrastructure.Persistence.Behaviors;

public class TransactionBehavior<TDbContext, TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse> where TDbContext : AppDbContext
{
    ILogger _logger;
    TDbContext _dbContext;
    public TransactionBehavior(TDbContext dbContext, ILogger logger)
    {
        _dbContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));
        _logger = logger ?? throw new ArgumentNullException(nameof(logger));
    }


    /// <summary>
    /// 处理请求并执行事务逻辑
    /// </summary>
    /// <param name="request"></param>
    /// <param name="next"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
    {
        var response = default(TResponse);
        var typeName = request.GetGenericTypeName();

        try
        {
            // 如果数据库上下文已开启事务，则执行业务代码
            if (_dbContext.HasActiveTransaction)
            {
                return await next();
            }

            // 创建数据库执行策略，用于处理重试逻辑
            var strategy = _dbContext.Database.CreateExecutionStrategy();

            // 执行事务逻辑
            await strategy.ExecuteAsync(async () =>
            {
                Guid transactionId;
                using (var transaction = await _dbContext.BeginTransactionAsync())
                using (_logger.BeginScope("TransactionContext:{TransactionId}", transaction.TransactionId))
                {
                    _logger.LogInformation("----- 开始事务 {TransactionId} ({@Command})", transaction.TransactionId, typeName, request);

                    response = await next();

                    _logger.LogInformation("----- 提交事务 {TransactionId} {CommandName}", transaction.TransactionId, typeName);


                    await _dbContext.CommitTransactionAsync(transaction);

                    transactionId = transaction.TransactionId;
                }
            });

            return response;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理事务出错 {CommandName} ({@Command})", typeName, request);

            throw;
        }
    }
}

public class AppContextTransactionBehavior<TRequest, TResponse> : TransactionBehavior<AppDbContext, TRequest, TResponse> where TRequest : IRequest<TResponse>
{
    public AppContextTransactionBehavior(AppDbContext dbContext, ILogger<AppContextTransactionBehavior<TRequest, TResponse>> logger) : base(dbContext, logger)
    {
    }
}
